package net.alche.fa.core;

import net.alche.fa.core.model.DebugFall;
import net.alche.fa.core.model.FaValue;

import java.util.List;
import java.util.Map;

import javax.management.RuntimeErrorException;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;

import net.alche.al.util.AC;
import net.alche.fa.core.doing.FaLogUtil;

@SuppressWarnings("all")
public class FaException extends Exception {
  public static String CODE_TYPE_ERROR = "data_type_error";
  public static String NULL_ERROR = "null_error";
  public static String LESS_METHOD = "less_method";
  public static String LESS_PARAM = "less_param";
  public static String VAR_NODE_DEFINE = "var_not_define";
  public static String CLASS_NOT_FIND = "class_not_find";
  public static String CLASS_CAN_NOT_NEW = "class_can_not_new";
  public static String NO_SUCH_FIELD = "no_such_field";
  public static String PARSE_CODE_ERROR = "parse_code_error";
  public static String NO_SUCH_CLASS = "no_such_class";
  public static String NO_DEFINE_VAR = "no_define_var";
  public static String URL_404 = "404";
  public static String FOR_OVER_TIMES = "for_over_times";
  public static String USER_STOP = "user_stop";
  String error;
  String errorCode;
  String coderTxt;
  String lineNum;
  DebugFall debugFall;
  Exception ex;
  CodeLevel codeLv;
  public FaValue favExcepton;

  public FaException() {
  }

  public FaException(FaValue favExcepton) {
    this.favExcepton = favExcepton;
  }

  public FaException(Exception ex) {
    if (ex instanceof InvocationTargetException) {
      InvocationTargetException ie = (InvocationTargetException) ex;
      Throwable th = ie.getTargetException();
      this.error = th.getMessage();
      this.errorCode = th.getClass().getSimpleName();
      return;
    }
    this.error = ex.getMessage();
    this.errorCode = ex.getClass().getSimpleName();
    this.ex = ex;
  }

  public FaException(String errorCode, String error) {
    this.errorCode = errorCode;
    this.error = error;
  }

  public FaException(String errorCode, String error, String remark) {
    this.errorCode = errorCode;
    this.error = error;
  }

  public List<Map> getDeepData() {
    DebugFall debug = this.debugFall;
    List<Map> list = new ArrayList<>();
    Map map = null;
    while (debug != null) {
      if (debug.getNum() != null) {
        map = new HashMap<>();
        map.put("num", debug.getNum());
        map.put("className", debug.getPrefix());
        map.put("method", debug.getCodeStr());
        list.add(map);
      }
      debug = debug.getPar();
    }
    return list;
  }

  public String getDeepError() {
    String txt = "";
    if (AC.notEmpty(error)) {
      txt = "#!#ERROR: " + this.getError();
    } else {
      txt = "#!#ERROR: " + this.getErrorCode();
    }
    DebugFall debug = this.debugFall;
    while (debug != null) {
      if (debug.getNum() != null) {
        txt = "#!#" + txt;
        txt = debug.getNum() + ": " + (debug.getPrefix() != null ? debug.getPrefix() + " " : " ") + debug.getCodeStr()
            + txt;
      }
      debug = debug.getPar();
    }
    return txt;
  }

  public String getError() {
    return error;
  }

  public void setError(String error) {
    this.error = error;
  }

  public String getErrorCode() {
    return errorCode;
  }

  public void setErrorCode(String errorCode) {
    this.errorCode = errorCode;
  }

  public String getLineNum() {
    return lineNum;
  }

  public void setLineNum(String lineNum) {
    this.lineNum = lineNum;
  }

  public String getCoderTxt() {
    return coderTxt;
  }

  public void setCoderTxt(String coderTxt) {
    this.coderTxt = coderTxt;
  }

  public DebugFall getDebugFall() {
    return debugFall;
  }

  public void setDebugFall(DebugFall debugFall) {
    this.debugFall = debugFall;
  }

  public void setCodeLevel(CodeLevel codeLv) {
    this.codeLv = codeLv;
  }

  public String getMessage() {
    String txt = this.getDeepError();
    if (favExcepton != null) {
      txt += "#!#" + this.getFaExMsg();
    }
    return txt;
  }

  public String getFaExMsg() {
    String txt = "";
    try {
      FaValue fav = favExcepton.getSageValue().getFaClass().call("getMessage", null, FaUtil.newCodeLvl());
      txt = fav.getStrValue();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return txt;
  }

  // 打印异常信息
  public void printStackTrace() {
    if (this.ex != null) {
      this.ex.printStackTrace();
    }
    FaLogUtil.logException(this.getDeepError(), this.codeLv);
  }
}